#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wbio.h"
#include "wblib.h"

#include "NUC900_reg.h"

#include "nvtfat.h"


#define UPSCR0		0xB0005064	/* USB Port0 Status and Control Register */
#define UPSCR1		0xB0005068	/* USB Port1 Status and Control Register */


extern int  get_item_number(int max);


#define DUMMY_BUFFER_SIZE		8192
static UINT8  _pucDummy[DUMMY_BUFFER_SIZE];



static INT  Action_DIR(CHAR *suDirName)
{
	INT				i, nStatus;
	CHAR			szMainName[12], szExtName[8], *pcPtr;
	CHAR			szLongName[MAX_FILE_NAME_LEN/2];
	FILE_FIND_T  	tFileInfo;
	UINT32 			uBlockSize, uFreeSize, uDiskSize;

	memset((UINT8 *)&tFileInfo, 0, sizeof(tFileInfo));
	nStatus = fsFindFirst(suDirName, NULL, &tFileInfo);
	if (nStatus < 0)
		return nStatus;

	do 
	{
		pcPtr = tFileInfo.szShortName;
		if ((tFileInfo.ucAttrib & A_DIR) && 
			(!strcmp(pcPtr, ".") || !strcmp(pcPtr, "..")))
			strcat(tFileInfo.szShortName, ".");

		memset(szMainName, 0x20, 9);
		szMainName[8] = 0;
		memset(szExtName, 0x20, 4);
		szExtName[3] = 0;
		i = 0;
		while (*pcPtr && (*pcPtr != '.'))
			szMainName[i++] = *pcPtr++;
		if (*pcPtr++)
		{
			i = 0;
			while (*pcPtr)
				szExtName[i++] = *pcPtr++;
		}

		fsUnicodeToAscii(tFileInfo.suLongName, szLongName, 1);
		
		if (tFileInfo.ucAttrib & A_DIR)
			sysprintf("%s %s      <DIR>  %02d-%02d-%04d  %02d:%02d  %s\n",
						szMainName, szExtName, 
						tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100 ,
						tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
		else
			sysprintf("%s %s %10d  %02d-%02d-%04d  %02d:%02d  %s\n",
						szMainName, szExtName, tFileInfo.n64FileSize,
						tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100 ,
						tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
	} while (!fsFindNext(&tFileInfo));
	
	fsFindClose(&tFileInfo);
	
	fsDiskFreeSpace('C', &uBlockSize, &uFreeSize, &uDiskSize);
	
	sysprintf("\nDisk Size: %d Kbytes, Free Space: %d KBytes\n", (INT)uDiskSize, (INT)uFreeSize);

	return 0;
}


static INT  Action_WriteSpeedTest(CHAR *suFileName, CHAR *szAsciiName)
{
	INT	 	 hFile;
	INT      i, j, nWriteLen, nTime0, nStatus;
	UINT32   uKBCnt = 0;

	hFile = fsOpenFile(suFileName, szAsciiName, O_CREATE | O_TRUNC);
	if (hFile < 0)
		return hFile;
		
	for (i = 0, j = 0; i < DUMMY_BUFFER_SIZE; i += 2, j++)
	{
		_pucDummy[i] = (j >> 8) & 0xff;
		_pucDummy[i + 1] = j & 0xff;
	}
	memset((UINT8 *)_pucDummy + 0x7e0, 0x97, 32);
		
	nStatus = 0;
	nTime0 = sysGetTicks(TIMER0);

	while (1)
	{
		nStatus = fsWriteFile(hFile, (UINT8 *)_pucDummy, DUMMY_BUFFER_SIZE, &nWriteLen);
		if (nStatus < 0)
			break;
		
		uKBCnt += nWriteLen / 1024;
		
		if (uKBCnt % 1024 == 0)
			sysprintf("%d MB\r", uKBCnt / 1024);
		
		if (uKBCnt >= 4 * 1024)
			break;
	}
	nTime0 = sysGetTicks(TIMER0) - nTime0;
	if (nTime0 == 0) nTime0 = 1;

	sysprintf("Write speed: %d KB/sec\n", (INT)(uKBCnt * 100) / nTime0);
	
	fsCloseFile(hFile);

	return nStatus;
}



static INT  Action_Compare(CHAR *suFileName1, CHAR *szAsciiName1, 
							CHAR *suFileName2, CHAR *szAsciiName2)
{
	INT		hFile1, hFile2;
	INT		nLen1, nLen2, nCount, nStatus1, nStatus2;
	UINT8	buffer1[8192], buffer2[8192];
	
	hFile1 = fsOpenFile(suFileName1, szAsciiName1, O_RDONLY);
	if (hFile1 < 0)
		return hFile1;
	
	hFile2 = fsOpenFile(suFileName2, szAsciiName2, O_RDONLY);
	if (hFile2 < 0)
		return hFile2;
	
	sysprintf("\nComparing file ...");
	nCount = 0;
	while (1)
	{
		nStatus1 = fsReadFile(hFile1, buffer1, 1024, &nLen1);
		nStatus2 = fsReadFile(hFile2, buffer2, 1024, &nLen2);
		
		if ((nStatus1 == ERR_FILE_EOF) && (nStatus2 == ERR_FILE_EOF))
		{
			sysprintf("OK!\n");
			fsCloseFile(hFile1);
			fsCloseFile(hFile2);
			return 0;
		}
		
		if (nLen1 != nLen2)
			break;
			
		if (memcmp(buffer1, buffer2, 1024))
			break;
		
		nCount++;
		//if ((nCount % 1024) == 0)
		//	sysprintf("%d KB    \r", nCount);
	}
	
	sysprintf("\nFile Compare failed at offset %x\n", nCount * 1024);
	
	fsCloseFile(hFile1);
	fsCloseFile(hFile2);
	return -1;
}


INT  find_usb_disk()
{
	PDISK_T		*pDiskList, *ptPDiskPtr;
	INT         driveNo;
	
	ptPDiskPtr = pDiskList = fsGetFullDiskInfomation();
	
	while (ptPDiskPtr != NULL)
	{
		if (ptPDiskPtr->nDiskType & DISK_TYPE_USB_DEVICE)
		{
			driveNo = ptPDiskPtr->ptPartList->ptLDisk->nDriveNo;
			fsReleaseDiskInformation(pDiskList);
			return driveNo;
		}
		ptPDiskPtr = ptPDiskPtr->ptPDiskAllLink;
	}
	fsReleaseDiskInformation(pDiskList);
	return -1;
}


int usbh_test1()
{
	CHAR 			croot[] = {'C',0,':',0,'\\',0,0,0};
	CHAR            test[]  = {'C',0,':',0,'\\',0,'T',0,'1',0,'1',0,'1',0,0,0};
	CHAR            test1[] = {'C',0,':',0,'\\',0,'T',0,'2',0,'2',0,'2',0,'2',0,0,0};
	INT				driveNo;
	INT				nStatus = 0;

	Hub_CheckIrqEvent();

	Hub_CheckIrqEvent();

	Hub_CheckIrqEvent();

	driveNo  = find_usb_disk();
	if (driveNo < 0)
	{
		sysprintf("USB Disk not found! Test failed!\nPress any key to continue...\n");
		sysGetChar();
		return -1;
	}

	croot[0] = driveNo;
	test[0]  = driveNo;
	test1[0] = driveNo;

	Action_DIR(croot);
	
	nStatus = Action_WriteSpeedTest(test, NULL);
	if (nStatus < 0)
		goto failed;
		
	fsDeleteFile(test1, NULL);

	sysprintf("Copying file...");
	nStatus = fsCopyFile(test, NULL, test1, NULL);
	if (nStatus < 0)
		goto failed;

	sysprintf("OK.\n");

	nStatus = Action_Compare(test, NULL, test1, NULL);
	if (nStatus < 0)
		goto failed;
	
	fsDeleteFile(test, NULL);
	fsDeleteFile(test1, NULL);
		
	sysprintf("USB Host test OK.\nPress any to to continue....\n");
	sysGetChar();
	return 0;
	
failed:
	sysprintf("Test failed, status = %x\n", nStatus);
	sysprintf("Press any to to continue....\n");
	sysGetChar();
	return -1;
}


int diag_usbh()
{
	while (1)
	{
		sysprintf("\n\n\n\n");
		sysprintf("+-------------------------------------------+\n");
		sysprintf("|  USB Host Test Items                      |\n");
		sysprintf("+-------------------------------------------+\n");
		sysprintf("(1) EHCI with USB 2.0 mass storage device   |\n");
		sysprintf("(2) EHCI split transfer                     |\n");
		sysprintf("(3) OHCI with USB 1.1 mass storage device   |\n");
		sysprintf("(4) Eye diagram test                        |\n");
		sysprintf("(0) Exit                                    |\n");
		sysprintf("+-------------------------------------------+\n");

		switch (get_item_number(5))
		{
			case 0:
				return (0);
				
			case 1:
				sysprintf("\n\nEHCI with USB 2.0 mass storage device test ...\n");
				sysprintf("Please plug any USB 2.0 mass storage device into USB port.\n");
				sysprintf("If you have plugged the USB device, press any key to continue ===>");
				sysGetChar();
				sysprintf("\n\n");
				usbh_test1();
				break;

			case 2:
				sysprintf("\n\nEHCI split transfer test ...\n");
				sysprintf("Please plug the USB 2.0 Hub into USB port of evaluation board.\n");
				sysprintf("And plug an USB 1.1 mass storage device under the USB Hub.\n");
				sysprintf("If ready, press any key to continue ===>");
				sysGetChar();
				sysprintf("\n\n");
				usbh_test1();
				break;

			case 3:
				sysprintf("\n\nEHCI with USB 1.1 mass storage device test ...\n");
				sysprintf("Please plug any USB 1.1 mass storage device into USB port.\n");
				sysprintf("If you have plugged the USB device, press any key to continue ===>");
				sysGetChar();
				sysprintf("\n\n");
				usbh_test1();
				break;

			case 4:
				sysprintf("\n\nEye diagram test ...\n");
				sysprintf("After connect USB host to test equipment, press any key...\n");
				sysGetChar();
				outpw(0xB0005064, inpw(0xB0005064) | 0x40000);
				outpw(0xB0005068, inpw(0xB0005068) | 0x40000);
				sysprintf("\n\nUSB Host enter test mode.\n");
				sysprintf("\n\nPress any key to leave test mode...\n");
				sysGetChar();
				outpw(0xB0005064, inpw(0xB0005064) & ~0x40000);
				outpw(0xB0005068, inpw(0xB0005068) & ~0x40000);
				break;

			case 5:
				usbh_test1();
				break;
		}
	}
	return 0;
}


